//
//  AkiraTextField.swift
//  TextFieldEffects
//
//  Created by Mihaela Miches on 5/31/15.
//  Copyright (c) 2015 Raul Riera. All rights reserved.
//

import UIKit

/**
 An AkiraTextField is a subclass of the TextFieldEffects object, is a control that displays an UITextField with a customizable visual effect around the edges of the control.
 */
open class AkiraTextField: TextFieldEffects {
  private let borderSize: (active: CGFloat, inactive: CGFloat) = (1, 2)
  private let borderLayer = CALayer()
  private let textFieldInsets = CGPoint(x: 6, y: 0)
  private let placeholderInsets = CGPoint(x: 6, y: 0)
  private var animationType: AnimationType = .textDisplay
  
  /// The color of the border.
  ///
  /// This property applies a color to the bounds of the control. The default value for this property is a clear color.
  open var borderColor: UIColor? {
    didSet {
      updateBorder()
    }
  }
  
  /// The color of the placeholder text.
  ///
  /// This property applies a color to the complete placeholder string. The default value for this property is #3D3D424C.
  open var placeholderColor: UIColor = UIColor(red: 0.24, green: 0.24, blue: 0.26, alpha: 0.3) {
    didSet {
      updatePlaceholder()
    }
  }
  
  /// The scale of the placeholder font.
  ///
  /// This property determines the size of the placeholder label relative to the font size of the text field.
  open var placeholderFontScale: CGFloat = 0.7 {
    didSet {
      updatePlaceholder()
    }
  }
  
  open override var placeholder: String? {
    didSet {
      updatePlaceholder()
    }
  }
  
  open override var bounds: CGRect {
    didSet {
      updateBorder()
    }
  }
  
  // MARK: TextFieldEffects
  
  open override func drawViewsForRect(_ rect: CGRect) {
    updateBorder()
    updatePlaceholder()
    
    addSubview(placeholderLabel)
    layer.addSublayer(borderLayer)
  }
  
  open override func animateViewsForTextEntry() {
    animationType = .textEntry
    UIView.animate(withDuration: 0.3) {
      self.updateBorder()
      self.updatePlaceholder()
    } completion: { _ in
      self.animationCompletionHandler?(.textEntry)
    }
  }
  
  open override func animateViewsForTextDisplay() {
    animationType = .textDisplay
    UIView.animate(withDuration: 0.3) {
      self.updateBorder()
      self.updatePlaceholder()
    } completion: { _ in
      self.animationCompletionHandler?(.textDisplay)
    }
  }
  
  // MARK: Private
  
  private func updateBorder() {
    borderLayer.frame = rectForBounds(bounds)
    borderLayer.borderWidth = (isFirstResponder || text?.isEmpty == false) ? borderSize.active : borderSize.inactive
    borderLayer.borderColor = borderColor?.cgColor
  }
  
  private func updatePlaceholder() {
    placeholderLabel.frame = placeholderRect(forBounds: bounds)
    placeholderLabel.text = placeholder
    placeholderLabel.font = placeholderFontFromFont(font)
    placeholderLabel.textColor = placeholderColor
    placeholderLabel.textAlignment = textAlignment
  }
  
  private func placeholderFontFromFont(_ font: UIFont?) -> UIFont {
    guard let font else { return UIFont() }
    return UIFont(descriptor: font.fontDescriptor, size: font.pointSize * placeholderFontScale)
  }
  
  private var placeholderHeight: CGFloat {
    return placeholderInsets.y + (font?.lineHeight ?? 0) * placeholderFontScale
  }
  
  private func rectForBounds(_ bounds: CGRect) -> CGRect {
    return CGRect(x: bounds.origin.x, y: bounds.origin.y + placeholderHeight, width: bounds.size.width, height: bounds.size.height - placeholderHeight)
  }
  
  // MARK: - Overrides
  
  open override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
    if animationType == .textEntry {
      return CGRect(x: placeholderInsets.x, y: placeholderInsets.y, width: bounds.width, height: placeholderHeight)
    } else {
      return textRect(forBounds: bounds)
    }
  }
  
  open override func editingRect(forBounds bounds: CGRect) -> CGRect {
    return textRect(forBounds: bounds)
  }
  
  open override func textRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.offsetBy(dx: textFieldInsets.x, dy: textFieldInsets.y + placeholderHeight / 2)
  }
}
